package wili.insertCode;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import wili.c.Str9a;
import wili.c.src.AnnotationsInds;
import wili.c.src.JaMethodInds;

/**
 * @author weila 2022年6月23日
 */
public class MethodPart implements Cloneable {
	public final int from, to;

	public String name;

	final int nameInd;

	public BracketPart body;

	public Method method;

	/**
	 * eg. int abc() throws Exception
	 */
	public String headSt;

	public int headInd;

	public String retTypeSt, paramSt, throwsSt;

	public ClassPart clsPart;

	List<String> paramTypes = Coms2.emptyList(), paramNames = Coms2.emptyList();

	final AnnotationsInds preAnnots;

	Cont cont;

	public String toString() {
		if (paramTypes.isEmpty())
			return clsPart.cname + "." + name + "()";
		String st = paramTypes.toString();
		st = st.substring(1, st.lastIndexOf(']'));
		st = clsPart.cname + "." + name + "(" + st + ")";
		return st.replaceFirst("//[^\n]*\n", "").replaceAll("\\s+", "");//eg. 以行注释结束另起新行继续
	}

	public MethodPart(JaMethodInds inds, ClassPart cls, Cont cont) {
		/*
			if retur type is "List<int[]>"?
			 
		 */
		if (inds.startInd == 921)
			Coms2.pause();
		this.preAnnots = inds.preAnnots;
		this.from = inds.startInd;
		this.to = inds.endInd;
		this.name = inds.name;
		this.method = (Method) inds.method;
		this.headSt = inds.headSt;
		this.headInd = inds.headFrom;
		this.throwsSt = inds.throwsSt;
		this.paramSt = inds.paramsSt;
		{//parse return type
			cls.file.s0.substring(this.from);
			String st = headSt.substring(0, headSt.indexOf('('));
			int ind2 = st.lastIndexOf(name);
			this.nameInd = this.headInd + ind2;
			st = st.substring(0, ind2).trim();
			{
				//eg. static List<Map<String, List<FmCharToExp>>>
				String st2 = Str9a.replaceNestWithStringOrChars(false, st, "<>", '.');
				int ind = st2.lastIndexOf(' ');
				if (ind != -1) {
					this.retTypeSt = st.substring(ind + 1).trim();
				} else {
					this.retTypeSt = st.trim();
				}
			}
		} //parse params.
		if (paramSt.isEmpty()) {
		} else {
			//eg. fun(String itemCode, String treeType /* = EMPTY_STR */)
			if (paramSt.contains("/*"))
				Coms2.pause();
			String paramSt2 = Str9a.replaceNestWith_string(paramSt, " ", "<>()");//space is need, eg. List<BmoBTNT>dtBTNT
			paramSt2 = Str9a.replaceStrRange(paramSt2, "/*", "*/", " ").trim();
			String[] pp = paramSt2.split(",");
			paramNames = new ArrayList<>(pp.length);
			paramTypes = new ArrayList<>(pp.length);
			//Class<?> ...clazz
			for (String namVal : pp) {
				namVal = namVal.trim();
				int ind = namVal.lastIndexOf("...");//eg. Class<?> ...clazz, String...bb
				if (ind > 0) {
					ind += 3;
				} else {
					ind = namVal.lastIndexOf(']');//eg. (String[]argc, String []argc
					if (ind > 0) {
						ind += 1;
					} else {
						ind = namVal.lastIndexOf(' ');
						Coms2.asert(ind > 0);
					}
				}
				paramTypes.add(namVal.substring(0, ind).trim());
				paramNames.add(namVal.substring(ind).trim());
			}
		}
		clsPart = cls;
		this.cont = cont;
	}

	public boolean isConstructor() {
		return name.equals(clsPart.cname);
	}

	public String getParamNameList() {
		if (this.paramNames.isEmpty())
			return "";
		StringBuilder sb = new StringBuilder();
		//sb.append(name + "(");
		if (paramNames != null) {
			for (int i = 0; i < this.paramNames.size(); i++) {
				if (i > 0)
					sb.append(",");
				String pm = paramNames.get(i);
				sb.append(pm);
			}
		}
		//sb.append(")");
		return sb.toString();
	}

	public void setBody(BracketPart part) {
		this.body = part;
	}

	public void rename(String newName) {
		this.clsPart.file.addInsert(this.nameInd, newName, name.length());
		this.name = newName;
	}

	public void setPrivateModifier() {
		if (!this.clsPart.isClass())
			return;
		final String s0 = this.clsPart.file.src_blankComment;
		final String leftName = s0.substring(this.headInd, this.nameInd);
		if (!leftName.replaceFirst("\\s(private|final)\\s", "").equals(leftName)) {
			return;//already private or final.
		}
		String newLeftName = leftName.replaceFirst("(\\s)(public|protected)(\\s)", "$1private$3");
		if (newLeftName.equals(leftName)) {
			newLeftName = leftName.replaceFirst("[^\\s]", "private $0");
		}
		//System.out.println(s0.substring(this.headInd, this.headInd + 100));
		this.clsPart.file.addInsert(this.headInd, newLeftName, leftName.length());
	}

	private Boolean isStatic;

	public boolean isStatic() {
		if (isStatic != null)
			return isStatic;
		return isStatic = !this.headSt.replaceFirst("[\\W]static[\\W]", "").equals(this.headSt);
	}

	public MethodPart clone() {
		MethodPart ret;
		try {
			ret = (MethodPart) super.clone();
			return ret;
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException(e);
		}
	}
}
